#include "bootpack.h"

#define EFLAGS_AC_BIT       0x00040000
#define CR0_CACHE_DISABLE   0x60000000

unsigned int memtest(unsigned int start, unsigned int end)
{
    char flg486 = 0;
    unsigned int eflag, cr0, tmp;

    /* 确认CPU是386或486 */
    eflag = io_load_eflags();
    eflag |= EFLAGS_AC_BIT;     /* AC-bit = 1 */
    io_store_eflags(eflag);
    eflag = io_load_eflags();
    if ((eflag & EFLAGS_AC_BIT) != 0) {
        flg486 = 1;
    }
    eflag &= ~EFLAGS_AC_BIT;   /* AC-bit = 0 */
    io_store_eflags(eflag);

    if (flg486 != 0) {
        cr0 = load_cr0();
        cr0 |= CR0_CACHE_DISABLE;   /* disable cache */
        store_cr0(cr0);
    }

    tmp = memtest_sub(start, end);
    if (flg486 != 0) {
        cr0 = load_cr0();
        cr0 &= ~CR0_CACHE_DISABLE;  /* able cache */
        store_cr0(cr0);
    }

    return tmp;
}

void memman_init(struct MEMMAN *man)
{
    man->frees = 0;     /* 可用数量 */
    man->maxfrees = 0;  /* 用于观察可用状态 */
    man->lostsize = 0;  /* 释放失败空间大小 */
    man->losts = 0;     /* 释放失败次数 */
    return;
}

unsigned int memman_total(struct MEMMAN *man)
/* get free memory total */
{
    unsigned int i, t = 0;
    for (i = 0; i < man->frees; i++) {
        t += man->free[i].size;
    }
    return t;
}

unsigned int memman_alloc(struct MEMMAN *man, unsigned int size)    /* malloc */
{
    unsigned int i, a;
    for (i = 0; i < man->frees; i++)
    {
        if (man->free[i].size >= size)  /* alloc memory succeed */
        {
            a = man->free[i].addr;
            man->free[i].addr += size;
            man->free[i].size -= size;
            if (man->free[i].size == 0)
            {
                man->frees--;
                for (; i < man->frees; i++)
                {
                    man->free[i] = man->free[i + 1];
                }
            }
            return a;
        }
    }
    return 0;   /* alloc memory fail */
}

int memman_free(struct MEMMAN *man, unsigned int addr, unsigned int size)   /* free */
{
    int i, j;
    for (i = 0; i < man->frees; i++)
    {
        if (man->free[i].addr > addr)
        {
            break;
        }
    }
    /* free[i-1].addr < addr < free[i].addr */
    if (i > 0)  
    {
        /* 前面有可用内存 */
        if (man->free[i-1].addr + man->free[i-1].size == addr)
        {
            man->free[i-1].size += size;
            if (i < man->frees)
            {
                if (addr+size == man->free[i].addr)    /* 后面也有 */
                {
                    man->free[i-1].size += man->free[i].size;
                    man->frees--;
                    for (; i < man->frees; i++)
                    {
                        man->free[i] = man->free[i+1];
                    }
                }
            }
            return 0;   /* freed successful */
        }
    }
    if (i < man->frees)
    {
        if (addr+size == man->free[i].addr)
        {
            man->free[i].addr = addr;
            man->free[i].size += size;
            return 0;   /* freed successful */
        }
    }
    if (man->frees < MEMMAN_FREES)
    {
        for (j = man->frees; j > i; j--)
        {
            man->free[j] = man->free[j-1];
        }
        man->frees++;
        if (man->maxfrees < man->frees)
        {
            man->maxfrees = man->frees;
        }
        man->free[i].addr = addr;
        man->free[i].size = size;
        return 0;   /* freed successful */
    }
    /* 不能后移 */
    man->losts++;
    man->lostsize += size;
    return -1; /* free fail */
}

unsigned int memman_alloc_4k(struct MEMMAN *man, unsigned int size)
{
    unsigned int a;
    size = (size + 0xfff) & 0xfffff000;
    a = memman_alloc(man, size);
    return a;
}

int memman_free_4k(struct MEMMAN *man, unsigned int addr, unsigned int size)
{
    int i;
    size = (size + 0xfff) & 0xfffff000;
    i = memman_free(man, addr, size);
    return i;
}
